#include "nano_stopwatch.h"
#include "timer_list.h"
#include <stdio.h>
#include <stdlib.h>

#define TIMER_COUNT 10000
static unsigned long long ticks = 0;

typedef struct
{
    ltimer_t timer;
    int idx;
    int counter;
    int trigger_times;
} test_timer_t;

#define BENCHMARK_PRINT(_nsw, _count, _desc)                          \
    do {                                                              \
        double ns = nsw_elapsed_ns(&(_nsw));                          \
        printf("%-6s %d timers take %-10.fns, avg %-5.f ns\n", _desc, \
            (_count), ns, ns / (_count));                             \
    } while (0)

void debug_dump(ltimer_t* timer) {
    test_timer_t* obj = (test_timer_t*)timer;
    printf(
        "ticks(%llu) idx(%d) timeout(%llu) repeat(%llu) "
        "counter(%d) trigger_times(%d)\n",
        ticks, obj->idx, timer->timeout, timer->repeat, obj->counter,
        obj->trigger_times);
}

void on_timer(ltimer_t* timer) {
    static int counter = 0;
    test_timer_t* obj = (test_timer_t*)timer;
    if (obj->counter < 0) {
        obj->counter = counter;
    }
    ++obj->trigger_times;
    ++counter;
    // debug_dump(timer);
}

int main() {
    printf("sizeof(ltimer_mgr_t) = %zu, sizeof(ltimer_t) = %zu\n",
        sizeof(ltimer_mgr_t), sizeof(ltimer_t));
    ltimer_mgr_t timer_mgr;
    timer_mgr_init(&timer_mgr, 0);
    test_timer_t* timers =
        (test_timer_t*)malloc(sizeof(test_timer_t) * TIMER_COUNT);
    memset(timers, 0, sizeof(test_timer_t) * TIMER_COUNT);

    nsw_t nsw = nsw_init();
    for (int i = 0; i < TIMER_COUNT; ++i) {
        timers[i].idx = i;
        timers[i].counter = -1;
        timer_start(&timer_mgr, (ltimer_t*)&timers[i], on_timer, i,
            (i % 2) ? 0 : TIMER_COUNT);
    }
    BENCHMARK_PRINT(nsw, TIMER_COUNT, "insert");
    nsw_reset(&nsw);
    int trigger_count = 3;
    unsigned long long tick_count = trigger_count * TIMER_COUNT;
    for (ticks = 0; ticks < tick_count; ++ticks) {
        timer_tick(&timer_mgr, ticks);
    }
    BENCHMARK_PRINT(nsw, 3 * TIMER_COUNT, "tick");
    for (int i = 0; i < TIMER_COUNT; ++i) {
        test_timer_t* timer = &timers[i];
        int expected_trigger_count = (timer->idx % 2) ? 1 : trigger_count;
        if (timer->idx != timer->counter ||
            timer->trigger_times != expected_trigger_count) {
            printf(
                "error: timers[%d].id(%d) != counter(%d) or trigger_times(%d) "
                "!= expected_trigger_count(%d)\n",
                i, timer->idx, timer->counter, timer->trigger_times,
                expected_trigger_count);
            abort();
        }
    }
    return 0;
}